package com.andox.fn.inf.rpc.rest;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.andox.fn.inf.rpc.rest.common.ResponseFuture;
import com.andox.fn.inf.rpc.rest.exception.ServiceRuntimeException;
import com.andox.fn.inf.rpc.rest.serializer.Serializer;
import com.google.common.collect.Maps;


/**   
 * @ClassName:   RequestContext   
 * @Description: TODO  
 * @author:      Andox
 * @date:        2019年8月1日 下午3:55:54   
 *     
 */
public class RequestContext {
	private final static ThreadLocal<RequestContext> threadLocal = new ThreadLocal<RequestContext>() {
		protected RequestContext initialValue() {return new RequestContext();};
	};
	
	private java.util.Map<String, Object> properties = new ConcurrentHashMap<>();
	
	public static RequestContext instance() {
		return threadLocal.get();
	}
	
	public RequestContext reset() {
		this.properties.clear();
		return this;
	}
	
	public static void removeContext() {
		threadLocal.remove();
	}
	
	public <T> T getResponse(int timeoutInMilliseconds) {
		ResponseFuture rf = (ResponseFuture)this.getProperty(RequestContextConstants.RESPONSE_FUTURE, null);
		if (rf == null) {
			throw new RuntimeException("there are no ResponseFuture,");
		}
		
		RpcResponse ar = rf.get(timeoutInMilliseconds);
		if (ar != null) {
			Serializer s = (Serializer)this.getProperty(RequestContextConstants.SERIALIZER, null);
			if (ResponseCodes.SUCCESS.equals(ar.getCode())) {
				return s.unserializeFromString(ar.getData(), null);
			}else {
				throw new ServiceRuntimeException(ar.getMsg());
			}
		}
		
		throw new ServiceRuntimeException("");
	}
	
	public RequestContext putProperty(String key, Object value) {
		properties.put(key, value);
		return this;
	}
	
	public RequestContext putPropertyIfAbsent(String key, Object value) {
		properties.putIfAbsent(key, value);
		return this;
	}
	
	public String getStringProperty(String key, String defaultValue) {
		return (String)this.getProperty(key, defaultValue);
	}
	
	public String getStringProperty(String key) {
		return this.getStringProperty(key, null);
	}

	public Object getProperty(String key, Object defaultValue) {
		Object r = this.properties.get(key);
		return r == null ? defaultValue : r;
	}
	
	public Object getProperty(String key) {
		return this.getProperty(key, null);
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getTProperty(String key) {
		return (T)this.getProperty(key, null);
	}
	
	public Boolean getBooleanProperty(String key, Boolean defaultValue) {
		return (Boolean)this.getProperty(key, defaultValue);
	}
	
	public Boolean getBooleanProperty(String key) {
		return this.getBooleanProperty(key, null);
	}

	public Integer getIntegerProperty(String key, Integer defaultValue) {
		return (Integer)this.getProperty(key, defaultValue);
	}

	public Integer getIntegerProperty(String key) {
		return this.getIntegerProperty(key, null);
	}

	public Long getLongProperty(String key, Long defaultValue) {
		return (Long)this.getProperty(key, defaultValue);
	}

	public Long getLongProperty(String key) {
		return this.getLongProperty(key, null);
	}
	
	public Class<?> getClassProperty(String key, Class<?> defaultValue) {
		return (Class<?>)this.getProperty(key, defaultValue);
	}
	
	public Class<?> getClassProperty(String key) {
		return this.getClassProperty(key, null);
	}
	
	public Map<String, Object> copy(){
		return Maps.newHashMap(this.properties);
	}
}
